home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / t3_1 / sources.lha / sources / sys / buffer.t < prev    next >
Text File  |  1988-02-05  |  19KB  |  481 lines

  1. (herald buffer
  2.   (env tsys))
  3.  
  4. ;;; Copyright (c) 1985 Yale University
  5. ;;;     Authors: N Adams, R Kelsey, D Kranz, J Philbin, J Rees.
  6. ;;; This material was developed by the T Project at the Yale University Computer 
  7. ;;; Science Department.  Permission to copy this software, to redistribute it, 
  8. ;;; and to use it for any purpose is granted, subject to the following restric-
  9. ;;; tions and understandings.
  10. ;;; 1. Any copy made of this software must include this copyright notice in full.
  11. ;;; 2. Users of this software agree to make their best efforts (a) to return
  12. ;;;    to the T Project at Yale any improvements or extensions that they make,
  13. ;;;    so that these may be included in future releases; and (b) to inform
  14. ;;;    the T Project of noteworthy uses of this software.
  15. ;;; 3. All materials developed as a consequence of the use of this software
  16. ;;;    shall duly acknowledge such use, in accordance with the usual standards
  17. ;;;    of acknowledging credit in academic research.
  18. ;;; 4. Yale has made no warrantee or representation that the operation of
  19. ;;;    this software will be error-free, and Yale is under no obligation to
  20. ;;;    provide any services, by way of maintenance, update, or otherwise.
  21. ;;; 5. In conjunction with products arising from the use of this material,
  22. ;;;    there shall be no use of the name of the Yale University nor of any
  23. ;;;    adaptation thereof in any advertising, promotional, or sales literature
  24. ;;;    without prior written consent from Yale in each case.
  25. ;;;
  26.  
  27. ;;; (import pool structure)
  28. ;;; (import (let valid-spec?))
  29.  
  30. ;;; describe buffers
  31.  
  32. ;++ T3 plans include:
  33. ;++  buffered i/o; update mode; re-openability; seeking & telling;
  34. ;++  TCP/IP interface.
  35. ;++ Change internal names to %buffer
  36.  
  37. ;++ what should be integrated?
  38. ;++ pooled structures
  39. ;++ should these things have read-tables? probably.
  40.  
  41.  
  42.  
  43. ;;; Buffer management.
  44.  
  45. ;;; %buffer modes
  46.  
  47. ;;; Major modes
  48. (define-constant iob/closed      #x00)    ; mode field set to zero
  49. (define-constant iob/read        #x01)
  50. (define-constant iob/write       #x02)
  51. (define-constant iob/append      #x04)
  52. (define-constant iob/dump        #x08)    ;++ remove
  53. (define-constant iob/retrieve    #x10)   ;++ remove
  54. (define-constant iob/inquire     #x20)   ; used to get info about the file.
  55.  
  56. ;;; Minor modes
  57. (define-constant iob/interactive #x0100)
  58. (define-constant iob/permanent   #x0200)  ; cannot be closed
  59. (define-constant iob/socket      #x0400)  ; TCP/IP
  60. (define-constant iob/window      #x0800)  ;
  61. (define-constant iob/transcript  #x1000)  ;
  62.  
  63. ;;; Mode predicates
  64.  
  65. (define-integrable (iob-mode? mode type) (fxN= 0 (fx-and mode type)))
  66.  
  67. (define-integrable (iob-closed? iob)      (fx-zero? (iob-mode iob)))
  68. (define-integrable (iob-readable? iob)    (iob-mode? (iob-mode iob) iob/read))
  69. (define-integrable (iob-writable? iob)    (iob-mode? (iob-mode iob) iob/write))
  70. (define-integrable (iob-append? iob)      (iob-mode? (iob-mode iob) iob/append))
  71. (define-integrable (iob-inquire? iob)     (iob-mode? (iob-mode iob) iob/inquire))
  72. (define-integrable (iob-dump? iob)        (iob-mode? (iob-mode iob) iob/dump))
  73. (define-integrable (iob-retrieve? iob)    (iob-mode? (iob-mode iob) iob/retrieve))
  74.  
  75. (define-integrable (iob-interactive? iob) (iob-mode? (iob-mode iob) iob/interactive))
  76. (define-integrable (iob-permanent? iob)   (iob-mode? (iob-mode iob) iob/permanent))
  77. (define-integrable (iob-socket? iob)      (iob-mode? (iob-mode iob) iob/socket))
  78. (define-integrable (iob-window? iob)      (iob-mode? (iob-mode iob) iob/window))
  79. (define-integrable (iob-transcript? iob)  (iob-mode? (iob-mode iob) iob/transcript))
  80.  
  81. ;;; Convert a mode or mode list to an iob-mode.
  82.  
  83. (define (mode->iob-mode caller filespec modespec)
  84.   (labels (((major mode item)
  85.             (let ((val (case item
  86.                          ((in)          iob/read)
  87.                          ((out)         iob/write)
  88.                          ((inquire)     iob/inquire)
  89.                          ((append)      iob/append)
  90.                          ((dump)        (fx-ior iob/write iob/dump))
  91.                          ((retrieve)    (fx-ior iob/read iob/retrieve))
  92.                          (else          (mode-error item)))))
  93.               (fx-ior mode val)))
  94.          ((minor mode items)
  95.           (iterate loop ((mode mode) (items items))
  96.             (if (null? items)
  97.                 mode
  98.                 (let ((val (case (car items)
  99.                              ((interactive) iob/interactive)
  100.                              ((permanent)   iob/permanent)
  101.                              ((socket)      iob/socket)
  102.                              ((window)      iob/window)
  103.                              ((transcript)  iob/transcript)
  104.                              (else          (mode-error (car items))))))
  105.                   (loop (fx-ior mode val) (cdr items))))))
  106.          ((mode-error item)
  107.           (mode->iob-mode 
  108.            caller 
  109.            filespec
  110.            (error "bad file mode ~s in - (~s ~a ~s ...)~
  111.                   ~10tType (RET mode) to retry."
  112.                   item
  113.                   caller 
  114.                   (if (iob? filespec) (iob-id filespec) filespec)
  115.                   modespec))))
  116.     (if (pair? modespec)
  117.         (minor (major 0 (car modespec)) (cdr modespec))
  118.         (major 0 modespec))))
  119.                                
  120. (define (unsupported-mode-error proc filespec mode)
  121.   (error "unsupported file mode - (~s ~a ~s ...)~
  122.           ~10tType (RET modespec) to retry."
  123.           proc 
  124.           (if (iob? filespec) (iob-id filespec) filespec)
  125.           mode))
  126.                                
  127.  
  128. ;++ write-string, read-block, force-output, newline,
  129. ;++ peek-char, port->iob, close, and re-open can be flushed from
  130. ;++ IOB.
  131.  
  132. (define-structure-type iob
  133.                        id          ; pathname
  134.                        mode        ; type of buffer
  135.                        rt          ; read-table
  136.                        buffer      ; text to hold data (bytev?)
  137.                        offset      ; current position in buffer
  138.                        limit       ; end of data in buffer
  139.                        underflow   ; underflow procedure
  140.                        overflow    ; overflow procedure
  141.                        xeno        ; system dependent descriptor
  142.                                    ; or 'buffer.
  143.                        h           ; hpos
  144.                        prev-h      ; previous hpos
  145.                        v           ; vpos
  146.                        indent
  147.                        wrap-column
  148.                        line-length          
  149.                        eof-flag?
  150.   (((read-char       (#f obj))       (vm-read-char obj))
  151.    ((write-char      (#f obj) c)     (vm-write-char obj c))
  152.    ((maybe-read-char (#f obj))       (vm-maybe-read-char obj))
  153.    ((newline         (#f obj))       (vm-newline obj))
  154.    ((unread-char     (#f obj))       (vm-unread-char obj))
  155.    ((peek-char       (#f obj))       (vm-peek-char obj))
  156.    ((write-string    (#f obj) s)     (vm-write-string obj s))
  157.    ((force-output    (#f obj))       (vm-force-output obj))
  158.    ((read-block (#f obj) extend cnt)
  159.     (vm-read-block obj extend cnt))
  160.    ((hpos            (#f obj))      (if (iob-closed? obj)
  161.                                               (closed-port-error obj)
  162.                                               (iob-h obj)))
  163.    ((vpos            (#f obj))       (if (iob-closed? obj)
  164.                                                (closed-port-error obj)
  165.                                                (iob-v obj)))
  166.    ((line-length     (#f obj))       (iob-line-length obj))
  167.    ((set-line-length (#f obj) len)   (set (iob-line-length obj) len))
  168.    ((wrap-column     (#f obj))       (iob-wrap-column obj))
  169.    ((set-wrap-column (#f obj) len)   (set (iob-wrap-column obj) len))
  170.    ((input-port?     (#f obj))       (iob-readable? obj))
  171.    ((output-port?    (#f obj))       (iob-writable? obj))
  172.    ((interactive?    (#f obj))       (iob-interactive? obj))
  173.    ((port? self)                           (ignore self) '#t)
  174.    ((port->iob       (#f obj)) obj)
  175.    ((port-read-table (#f obj))
  176.     (cond ((iob-rt obj))
  177.           (else standard-read-table)))
  178.    ((set-port-read-table (#f obj) new-read-table)
  179.     (set (iob-rt obj) new-read-table))
  180.    ((port-name (#f obj))              (iob-id obj))
  181.    ((set-port-name (#f obj) name)     (set (iob-id obj) name))
  182.    ((close           (#f obj))        (close-port obj))
  183.    ((re-open         (#f obj) mode)   (re-open-port! obj mode))
  184.    ((display         (#f obj) stream)
  185.     (iterate loop ((i 0))
  186.       (let ((buffer (iob-buffer obj)))
  187.         (cond ((fx>= i (iob-offset obj)) (no-value))
  188.               (else
  189.                (vm-write-char stream (text-elt buffer i))
  190.                (loop (fx+ i 1)))))))
  191.    ((print (#f obj) stream)
  192.     (format stream "#{Port~_~a~_~a}"
  193.                     (iob-id obj)
  194.                     (object-hash obj)))))
  195.  
  196. ;++ initialize the STYPE master.
  197.  
  198. (define standard-line-length 80)
  199. (define standard-wrap-column (fx- standard-line-length 15))
  200.  
  201. (set (iob-id          (stype-master iob-stype)) nil)
  202. (set (iob-mode        (stype-master iob-stype)) iob/closed)
  203. (set (iob-buffer      (stype-master iob-stype)) '#f)
  204. (set (iob-eof-flag?   (stype-master iob-stype)) '#f)
  205. (set (iob-h           (stype-master iob-stype)) 0)
  206. (set (iob-prev-h      (stype-master iob-stype)) 0)
  207. (set (iob-v           (stype-master iob-stype)) 0)
  208. (set (iob-indent      (stype-master iob-stype)) 0)
  209. (set (iob-wrap-column (stype-master iob-stype)) standard-wrap-column)
  210. (set (iob-line-length (stype-master iob-stype)) standard-line-length)
  211. (set (iob-rt          (stype-master iob-stype)) '#f)
  212.  
  213. (define-constant buffer?       iob?)
  214. (define-constant buffer-length iob-offset)
  215. (define-constant buffer-text   iob-buffer)
  216. (define-constant (buffer-empty? iob)
  217.   (if (fx= (iob-offset iob) 0) '#t '#f))
  218.  
  219. (define buffer-elt
  220.   (object (lambda (iob n)
  221.             (text-elt (iob-buffer iob) n))  
  222.     ((setter self)
  223.      (lambda (iob n ch)
  224.        (let ((ch (enforce char? ch)))
  225.          (set (text-elt (iob-buffer iob) n) ch))))))
  226.  
  227. (define-integrable (max-buffer-length iob)
  228.   (text-length (iob-buffer iob)))
  229.  
  230. (define (buffer-fill! iob char count)
  231.   (let ((iob  (enforce buffer? iob))
  232.         (char (enforce char?   char)))
  233.     (do ((i 0 (fx+ i 1)))
  234.         ((fx>= i count))
  235.       (vm-write-char iob char)))
  236.    (no-value))
  237.  
  238. (define (buffer->string! b)
  239.   (let ((s (make-string 0)))
  240.     (set (string-text s)   (iob-buffer b))
  241.     (set (string-length s) (buffer-length b))
  242.     s))
  243.  
  244. (define (buffer->string iob)
  245.   (let* ((len  (buffer-length iob))
  246.          (str  (make-string len))
  247.          (text (string-text str)))
  248.     (move-text (iob-buffer iob) 0 text 0 len)
  249.     str))
  250.  
  251. (define (string->input-port str)
  252.   (let* ((len  (string-length str))
  253.          (iob  (get-buffer-of-size len))
  254.          (text (iob-buffer iob)))
  255.     (do ((i 0 (fx+ i 1)))
  256.         ((fx>= i len)
  257.          (set (iob-offset iob) 0)
  258.          (set (iob-limit iob)  len)
  259.          (set (iob-mode iob) iob/read)
  260.          iob)
  261.       (set (text-elt text i) (string-elt str i)))))
  262.  
  263. ;++ Should return an update port, but for now it returns an input
  264. ;++ port.
  265.  
  266. (define string->buffer string->input-port)
  267.  
  268. ;;; Make sure that the channel hasn't been closed
  269.  
  270. (define (iob-channel iob)
  271.   (if (iob-closed? iob) (closed-port-error iob) (iob-xeno iob)))
  272.  
  273. (define (closed-port-error iob)
  274.   (non-continuable-error "~s is closed." (iob-id iob)))
  275.  
  276.  
  277. ;++ Should this be lap? or primop. This uses indexing, on a machine
  278. ;++ with tags it would use pointers into objects.
  279. ;++ move it to the appropriate file.
  280.  
  281. (define-integrable (MOVE-TEXT SRC S-OFF DST D-OFF N)
  282.   (do ((n n (fx- n 1))
  283.        (s-off s-off (fx+ s-off 1))
  284.        (d-off d-off (fx+ d-off 1)))
  285.       ((fx<= n 0) (no-value))
  286.     (set (text-elt dst d-off) (text-elt src s-off))))
  287.  
  288. ;;; Make an I/O buffer.  Used by VM before pools are available.
  289.  
  290. (define (CREATE-IOB ID CHAN MODE SIZE)
  291.   (let ((iob (make-iob)))
  292.     (set (iob-buffer iob) (make-text size))
  293.     (initialize-iob iob id chan mode)))
  294.  
  295. (define (ensure-iob-size text-pool iob size)
  296.   (cond ((not (iob-buffer iob))
  297.          (set (iob-buffer iob) (obtain-from-pool (text-pool size))))
  298.         ((fx> size (max-buffer-length iob))
  299.          (let ((text (iob-buffer iob)))
  300.            (return-to-pool (text-pool (text-length text)) text)
  301.            (set (iob-buffer iob) (obtain-from-pool (text-pool size)))))))
  302.  
  303. (define (initialize-iob iob id chan mode)
  304.   (set (iob-id          iob) id)
  305.   (set (iob-mode        iob) mode)
  306.   (set (iob-offset      iob) 0)
  307.   (set (iob-xeno        iob) chan)
  308.   (set (iob-h           iob) 0)
  309.   (set (iob-prev-h      iob) 0)
  310.   (set (iob-v           iob) 0)
  311.   (set (iob-indent      iob) 0)
  312.   (set (iob-wrap-column iob) standard-wrap-column)
  313.   (set (iob-line-length iob) standard-line-length)
  314.   (set (iob-rt          iob) '#f)
  315.   (set (iob-eof-flag?   iob) '#f)
  316.   (cond ((iob-readable? iob)
  317.          (set (iob-limit iob) 0)
  318.          (set (iob-underflow iob) %vm-read-buffer)
  319.          (set (iob-overflow iob) overflow-error))
  320.         ((or (iob-writable? iob) (iob-append? iob))
  321.          (set (iob-limit iob) (max-buffer-length iob))
  322.          (set (iob-underflow iob) underflow-error)
  323.          (set (iob-overflow iob) (lambda (iob size)
  324.                                    (ignore size)
  325.                                    (%vm-write-buffer iob)))))
  326.   iob)
  327.  
  328. (define (overflow-error buf size)
  329.   (ignore size)
  330.   (error "buffer ~a overflowed." buf))
  331.  
  332. (define (underflow-error buf block?) (ignore buf block?) eof)
  333.  
  334. ;;; There are ten pools, for buffers of various sizes.
  335. ;;;    0    1    2    3     4     5     6     7      8      9
  336. ;;;   64  128  256  512  1024  2048  4096  8192  16834  32768
  337.  
  338. ;;; Return a pool from which one can obtain a buffer whose size
  339. ;;; is >= N.
  340.  
  341. (define (make-vector-of-pools maker type? min-size max-size)
  342.   (let ((pools (make-vector 10)))
  343.     (do ((i 0 (fx+ i 1))
  344.          (n min-size (fixnum-ashl n 1)))
  345.         ((fx> i 9))
  346.       (set (vref pools i)
  347.            (make-pool `(extend-pool ,i)
  348.                       (lambda () (maker n))
  349.                       1
  350.                       type?)))
  351.     (lambda (n)
  352.       (cond ((fx<= n min-size)
  353.              (vref pools 0))  ; speed hack for common case
  354.             (else
  355.              (let ((i (fixnum-howlong (fixnum-ashr (fx- n 1) 6))))
  356.                (if (fx> n max-size)
  357.                    (error "cannot allocate buffer of size ~a~%" n)
  358.                    (vref pools i))))))))
  359.  
  360.  
  361. (define-operation (obtain pool))
  362. (define-operation (release pool))
  363. (define-operation (release-buffer-text pool buffer))
  364. (define-operation (get-i/o-buffer pool id chan mode size))
  365.  
  366. ;;; Note: OVERFLOW below is a bit complicated and gross.  It makes
  367. ;;;       sure that the IOB can hold at least N additional characters.
  368. ;;;       If not the buffers size is increased by allocating a buffer
  369. ;;;       of the appropriate size, copying the contents of the old
  370. ;;;       buffer to the new, and finally exchanging the text pointers
  371. ;;;       of the two buffers creating a transparent side effect.
  372.  
  373. (define (make-buffer-pool)
  374.   (let* ((iob-pool  (make-pool 'buffer-pool make-iob 1 iob?))
  375.          (text-pool (make-vector-of-pools  make-text
  376.                                            text?
  377.                                            min-iob-size
  378.                                            max-iob-size))
  379.          (rel-text  (lambda (text)
  380.                       (return-to-pool
  381.                         (text-pool (text-length text)) text)))
  382.          (underflow (lambda (iob #f) (end-of-file iob)))
  383.          (overflow  (lambda (iob n)
  384.                       (let* ((old-size (text-length (iob-buffer iob)))
  385.                              (temp (obtain-from-pool
  386.                                     (text-pool (fx+ old-size n)))))
  387.                         (move-text (iob-buffer iob) 0 temp 0 old-size)
  388.                         (exchange (iob-buffer iob) temp)
  389.                         (return-to-pool (text-pool old-size) temp))
  390.                       (set (iob-limit iob) (max-buffer-length iob))
  391.                       (no-value)))
  392.          (get-buffer (lambda (mode size)
  393.                        (let ((iob  (obtain-from-pool iob-pool))
  394.                              (text (obtain-from-pool (text-pool size))))
  395.                          (set (iob-buffer iob) text)
  396.                          (init-buffer iob mode underflow overflow)))))
  397.     (object (lambda (mode size)
  398.               (get-buffer mode size))
  399.       ((obtain self)
  400.        (get-buffer iob/write 0))
  401.       ((release self obj)
  402.        (let* ((iob  (enforce iob? obj))
  403.               (text (iob-buffer iob)))
  404.          (set (iob-buffer iob) '#f)
  405.          (set (iob-id     iob) '#f)
  406.          (set (iob-xeno   iob) '#f)
  407.          (if text (rel-text text))
  408.          (return-to-pool iob-pool iob)))
  409.       ((release-buffer-text self obj)
  410.        (let ((iob (enforce iob? obj)))
  411.          (let ((text (iob-buffer iob)))
  412.            (set (iob-buffer iob) '#f)
  413.            (rel-text text))))
  414.       ((get-i/o-buffer self file chan mode size)
  415.        (receive (iob id)
  416.                 (if (iob? file)
  417.                     (return file (iob-id file))
  418.                     (return (obtain-from-pool iob-pool) file))
  419.          (ensure-iob-size text-pool iob size)
  420.          (initialize-iob iob id chan mode)))
  421.       ((pool-statistics self stream)
  422.        (pool-statistics iob-pool stream))
  423.       ((print-type-string self) "Buffer pool"))))
  424.  
  425. ;;; Initialize an ephemeral buffer
  426.  
  427. (define (init-buffer buf mode underflow overflow)
  428.   (set (iob-mode        buf) mode)
  429.   (set (iob-offset      buf) 0)
  430.   (set (iob-h           buf) 0)
  431.   (set (iob-prev-h      buf) 0)
  432.   (set (iob-v           buf) 0)
  433.   (set (iob-indent      buf) 0)
  434.   (set (iob-wrap-column buf) standard-wrap-column)
  435.   (set (iob-line-length buf) standard-line-length)
  436.   (set (iob-rt          buf) '#f)
  437.   (set (iob-eof-flag?   buf) '#f)
  438.   (cond ((iob-readable? buf)
  439.          (set (iob-limit     buf) 0)
  440.          (set (iob-underflow buf) underflow)
  441.          (set (iob-overflow  buf) overflow-error))
  442.         ((iob-writable? buf)
  443.          (set (iob-limit     buf) (max-buffer-length buf))
  444.          (set (iob-underflow buf) underflow-error)
  445.          (set (iob-overflow  buf) overflow)))
  446.   buf)
  447.  
  448.  
  449. ;;; T's internal buffers.  There used for real and ephemeral I/O.
  450. ;;; This stuff will eventually be eliminated and the higher level
  451. ;;; stuff above will replace it.
  452.  
  453. (define-constant min-iob-size 64)
  454. (define-constant max-iob-size 32768)
  455.  
  456. (define %buffer-pool (make-buffer-pool))
  457.  
  458. ;;; Obtain a small buffer.
  459.  
  460. (define-integrable (GET-BUFFER)
  461.   (%buffer-pool iob/write 0))
  462.  
  463. ;;; Obtain a buffer whose size is >= N.
  464.  
  465. (define-integrable (GET-BUFFER-OF-SIZE SIZE)
  466.   (let ((size (enforce fixnum? size)))
  467.     (%buffer-pool iob/write size)))
  468.  
  469. ;;; Release an iob.
  470.  
  471. (define-integrable (RELEASE-BUFFER iob)
  472.   (release %buffer-pool iob))
  473.  
  474. ;;; a portable interface to buffered i/o
  475.  
  476. (define (channel->port channel name modespec buffer-size)
  477.   (let* ((mode (mode->iob-mode 'channel->port name modespec))
  478.          (iob (get-i/o-buffer %buffer-pool name channel mode buffer-size)))
  479. ;++ (set (table-entry open-port-table iob) (object-hash iob))
  480.     iob))
  481.